package Word_Frequency;

import java.util.*;

class TextRankCalculator {
    private static final double DAMPING_FACTOR = 0.85;
    private static final int MAX_ITERATIONS = 100;
    private static final double MIN_DIFF = 0.01;

    private WordFrequency wordFrequency;

    public TextRankCalculator(WordFrequency wordFrequency) {
        this.wordFrequency = wordFrequency;
    }

    public Map<String, Double> calculateTextRank(String document) {
        List<String> words = wordFrequency.getWords(document);
        Map<String, Set<String>> wordGraph = buildWordGraph(words);
        Map<String, Double> scores = initializeScores(wordGraph);

        boolean converged;
        for (int i = 0; i < MAX_ITERATIONS; i++) {
            Map<String, Double> newScores = new HashMap<>();
            converged = true;
            for (String word : wordGraph.keySet()) {
                double score = 1 - DAMPING_FACTOR;
                for (String neighbor : wordGraph.get(word)) {
                    score += DAMPING_FACTOR * (scores.get(neighbor) / wordGraph.get(neighbor).size());
                }
                newScores.put(word, score);
                if (Math.abs(newScores.get(word) - scores.get(word)) > MIN_DIFF) {
                    converged = false;
                }
            }
            scores = newScores;
            if (converged) break;
        }
        return scores;
    }

    private Map<String, Set<String>> buildWordGraph(List<String> words) {
        Map<String, Set<String>> wordGraph = new HashMap<>();
        int windowSize = 5;
        for (int i = 0; i < words.size(); i++) {
            String word = words.get(i);
            if (!wordGraph.containsKey(word)) {
                wordGraph.put(word, new HashSet<>());
            }
            for (int j = Math.max(0, i - windowSize); j < Math.min(words.size(), i + windowSize + 1); j++) {
                if (i == j) continue;
                String neighbor = words.get(j);
                wordGraph.get(word).add(neighbor);
            }
        }
        return wordGraph;
    }

    private Map<String, Double> initializeScores(Map<String, Set<String>> wordGraph) {
        Map<String, Double> scores = new HashMap<>();
        for (String word : wordGraph.keySet()) {
            scores.put(word, 1.0);
        }
        return scores;
    }
}